/*
 * =====================================================================================
 *       Filename:  config.c
 *    Description:  配置相关代码
 *        Created:  2015-07-04 12:52
 *         Author:  mien, m@p58.net
 * =====================================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <fcntl.h>
#include "config.h"

#include "lib/dict.h"
#include "lib/zipmap.h"

static int _loaded = 0;
static dictTable *_config;

/* 合并路径与文件名 (没有检查缓冲区边界) */
static void pathJoin(char *path, const char *filename)
{
    const char *p = filename;
    if (p[0] == '/') {
        strcpy(path, p);
    } else {
        if (path[strlen(path) - 1] != '/') {
            strcat(path, "/");
        }
        if (p[0] == '.' && p[1] == '/') {
            p += 2;
        }
        strcat(path, p);
    }
}

/* 加载配置 */
void loadConfig(const char *path, const char *filename)
{
    if (_loaded) return;
    
    /* 临时缓冲区 */
    char buf[MAX_LINE_SIZE];
    char line[MAX_LINE_SIZE];
    char section[32];
 
    /* 更改工作路径 */
    strcpy(line, path);
    char *s = strrchr(line, '/');
    if (s != NULL) {
        *s = 0;
    }
    
    if (chdir(line) == -1){
        printf("Could not change current working diretory.\n");
        exit(1);
    }

    /* 打开配置文件 */
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("Could not find configure file '%s'.\n", filename);
        exit(1);
    }
    
    /* 用于保存配置的dict */
    _config = dictCreateWithSize(&dictTypeStringKeyVal, 32);

    /* 解析 */
    while (fgets(buf, MAX_LINE_SIZE, fp) != NULL) {
        /* 复制buf中的行字符到line中，去掉空格 */
        int i, j, flag, len;
        j = 0;
        flag = -1;
        for (i = 0; i < MAX_LINE_SIZE; i++) {
            if (buf[i] == ' ') continue;
            if (buf[i] == '\n' || buf[i] == '\r' || buf[i] == '\0') {
                line[j++] = '\0';
                break;
            }
            if (buf[i] == '=')
                flag = j;
            line[j++] = buf[i];
        }
        
        /* 忽略空行、注释行 */
        if (j < 2 || line[0] == '#') continue;
        
        /* 忽略格式错误的小节标记行 */
        if ((line[0] == '[' && line[j - 2] != ']') || (line[0] != '[' && line[j - 2] == ']'))
            continue; 
        
        /* 忽略格式错误的设置项行 */
        if (line[0] != '[' && flag <= 0) continue;
        
        /* 是小节 */
        if (line[0] == '[') {
            strncpy(section, line + 1, j - 3);
            section[j - 3] = '\0';
        }
        /* 是设置项 */
        else {
            line[flag] = '\0';
            sprintf(buf, "%s_%s", section, line);
            dictSet(_config, buf, line + flag + 1);
        }
    }

    /* 调整 queue_data_dir 为绝对路径 */
    strcpy(line, getcwd(NULL, 0));
    pathJoin(line, dictGet(_config, "queue_data_dir"));
    dictSet(_config, "queue_data_dir", line);

    /* 关闭 */
    fclose(fp);
    _loaded = 1;
}

void freeConfig()
{
    dictFree(_config);
}

void setUidGid()
{
    char *user  = getConfig("user_user");
    char *group = getConfig("user_group");

    if (user != NULL) {
        struct passwd *pwd;
        pwd = getpwnam(user);
        if (pwd != NULL)
            setuid(pwd->pw_uid);
    }
    if (group != NULL) {
        struct group *grp;
        grp = getgrnam(group);
        if (grp != NULL)
            setgid(grp->gr_gid);
    }
}

char *getConfig(char *key)
{
    return dictGet(_config, key);
}
